﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AcademiaEntidades;
using System.Data.SqlClient;
using System.Data;

namespace AcademiaDAO
{
    public enum DireccionOrden
    {
        Ascendente, Descendente
    }

    public class CobroDAO
    {
        public static List<Cobro> ObtenerTodos(string orden, int? idCobro, int? numeroFactura, int? idAlumno, DateTime? fechaDesde, DateTime? fechaHasta)
        {
            List<Cobro> cobros = new List<Cobro>();
            try
            {
                StringBuilder sb = new StringBuilder("SELECT IdCobro, NumeroFactura, IdAlumno, Fecha FROM Cobro WHERE 1=1 ");

                using (SqlConnection conn = AccesoDato.Conectar())
                {
                    SqlCommand cmd = new SqlCommand();
                    cmd.CommandType = System.Data.CommandType.Text;
                    cmd.Connection = conn;

                    if (idCobro.HasValue)
                    {
                        sb.Append(" AND IdCobro = @IdCobro");
                        cmd.Parameters.AddWithValue("@IdCobro", idCobro);
                    }

                    if (numeroFactura.HasValue)
                    {
                        sb.Append(" AND NumeroFactura = @NroFactura");
                        cmd.Parameters.AddWithValue("@NroFactura", numeroFactura);
                    }

                    if (idAlumno.HasValue)
                    {
                        sb.Append(" AND IdAlumno = @IdAlumno");
                        cmd.Parameters.AddWithValue("@IdAlumno", idAlumno);
                    }

                    if (fechaDesde.HasValue)
                    {
                        sb.Append(" AND Fecha >= @FechaIDesde");
                        cmd.Parameters.AddWithValue("@FechaDesde", fechaDesde);
                    }

                    if (fechaHasta.HasValue)
                    {
                        sb.Append(" AND Fecha <= @FechaHasta");
                        cmd.Parameters.AddWithValue("@FechaHasta", fechaHasta);
                    }

                    if (!string.IsNullOrEmpty(orden))
                    {
                        sb.Append(" ORDER BY ").Append(orden);
                    }

                    cmd.CommandText = sb.ToString();
                    conn.Open();
                    SqlDataReader dr = cmd.ExecuteReader();

                    while (dr.Read())
                    {
                        cobros.Add(MapearEntidadCobro(dr));
                    }
                }
                return cobros;
            }
            catch (SqlException ex)
            {
                throw new Exception("No se pudieron obtener los cobros");
            }
        }

        public static DataTable ObtenerTodosReporte(string orden, DireccionOrden direccion, int? legajoAlumno, int? idCobro, int? numeroFactura, string auxMonto, decimal? monto, string nombre, string apellido, DateTime? fechaDesde, DateTime? fechaHasta, out decimal montoTotal)
        {
            try
            {
                StringBuilder sb = new StringBuilder("SELECT c.IdCobro, c.NumeroFactura, (a.Apellido + ', ' + a.Nombre) AS 'Nombre', c.Fecha, SUM(dc.Monto) AS 'Monto' ");
                sb.Append("FROM Cobro c ");
                sb.Append("INNER JOIN DetalleCobro dc ON dc.IdCobro = c.IdCobro ");
                sb.Append("INNER JOIN Alumno a ON c.IdAlumno = a.IdAlumno ");
                sb.Append("WHERE 1=1 ");

                using (SqlConnection conn = AccesoDato.Conectar())
                {
                    SqlCommand cmd = new SqlCommand();
                    cmd.CommandType = System.Data.CommandType.Text;
                    cmd.Connection = conn;

                    if (legajoAlumno.HasValue)
                    {
                        sb.Append(" AND a.Legajo = @Legajo ");
                        cmd.Parameters.AddWithValue("@Legajo", legajoAlumno);
                    }

                    if (idCobro.HasValue)
                    {
                        sb.Append(" AND c.IdCobro = @IdCobro ");
                        cmd.Parameters.AddWithValue("@IdCobro", idCobro);
                    }

                    if (numeroFactura.HasValue)
                    {
                        sb.Append(" AND c.NumeroFactura = @NroFactura ");
                        cmd.Parameters.AddWithValue("@NroFactura", numeroFactura);
                        // cmd.Parameters.Add(new SqlParameter("@NroFactura", numeroFactura));
                    }

                    if (!string.IsNullOrEmpty(nombre))
                    {
                        sb.Append(" AND a.Nombre LIKE @Nombre ");
                        cmd.Parameters.AddWithValue("@Nombre", "%" + nombre + "%");
                    }

                    if (!string.IsNullOrEmpty(apellido))
                    {
                        sb.Append(" AND a.Apellido LIKE @Apellido ");
                        cmd.Parameters.AddWithValue("@Apellido", "%" + apellido + "%");
                    }
                    
                    if (fechaDesde.HasValue)
                    {
                        sb.Append(" AND Fecha >= @FechaDesde ");
                        cmd.Parameters.AddWithValue("@FechaDesde", fechaDesde);
                    }

                    if (fechaHasta.HasValue)
                    {
                        sb.Append(" AND Fecha <= @FechaHasta ");
                        cmd.Parameters.AddWithValue("@FechaHasta", fechaHasta);
                    }

                    sb.Append(" GROUP BY c.IdCobro, NumeroFactura, (a.Apellido + ', ' + a.Nombre), c.Fecha ");

                    if (monto.HasValue && !string.IsNullOrEmpty(auxMonto))
                    {
                        sb.Append(" HAVING SUM(dc.Monto) ").Append(auxMonto).Append(" ").Append(decimal.Parse(monto.ToString()).ToString(System.Globalization.CultureInfo.InvariantCulture));
                    }

                    if (!string.IsNullOrEmpty(orden))
                    {
                        string direccionAux = "ASC";
                        if (direccion == DireccionOrden.Descendente)
                        {
                            direccionAux = "DESC";
                        }

                        sb.Append(" ORDER BY ").Append(orden).Append(" ").Append(direccionAux);
                    }

                    cmd.CommandText = sb.ToString();

                    DataTable dt = new DataTable();
                    SqlDataAdapter da = new SqlDataAdapter(cmd);
                    da.Fill(dt);

                    var sum = dt.AsEnumerable().Sum(dr => dr.Field<decimal>("Monto"));
                    montoTotal = (decimal)sum;

                    return dt;
                }
            }
            catch (SqlException ex)
            {
                throw new Exception("No se pudieron obtener los cobros");
            }
        }

        public static DataTable ObtenerDetallesCobroReporte(int idCobro)
        {
            SqlConnection conn = null;
            StringBuilder sb = new StringBuilder("SELECT c.Nombre AS 'Curso', cm.NumeroCuota, dc.Monto FROM DetalleCobro dc ");
            sb.Append("INNER JOIN CuotaXMatricula cm ON dc.IdCuotaMatricula = cm.IdCuotaMatricula ");
            sb.Append("INNER JOIN Matricula m ON cm.IdMatricula = m.IdMatricula ");
            sb.Append("INNER JOIN Curso c ON m.IdCurso = c.IdCurso ");
            sb.Append("WHERE dc.IdCobro = @IdCobro");
            try
            {
                conn = AccesoDato.Conectar();
                SqlCommand cmd = new SqlCommand(sb.ToString(), conn);
                // cmd.Connection = conn;
                cmd.Parameters.AddWithValue("@IdCobro", idCobro);
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                DataTable dt = new DataTable();
                da.Fill(dt);
                return dt;

            }
            catch (SqlException ex)
            {
                throw new Exception("No se pudo obtener los detalles del cobro");
            }
            finally
            {
                if (conn != null && conn.State == ConnectionState.Open)
                {
                    conn.Close();
                }
            }
        }

        public static void Grabar(Cobro cobro, List<DetalleCobro> detalle)
        {
            SqlTransaction tran = null;
            SqlConnection conn = null;
            SqlCommand cmd = null;
            try
            {
                conn = AccesoDato.Conectar();
                conn.Open();
                tran = conn.BeginTransaction();
                cmd = new SqlCommand();
                cmd.CommandType = CommandType.Text;
                cmd.Connection = conn;
                cmd.Transaction = tran;

                StringBuilder sb = new StringBuilder();

                // se busca el próximo número de factura

                sb.Append("SELECT Numero FROM CobroAux ");
                cmd.CommandText = sb.ToString();
                cobro.NumeroFactura = int.Parse(cmd.ExecuteScalar().ToString());

                // se guarda el cobro

                sb.Clear(); // se limpia el string
                //cmd.Parameters.Clear(); // se limpian los parámetros

                sb.Append("INSERT INTO Cobro(NumeroFactura, IdAlumno, Fecha) VALUES(@NroFact, @IdAlu, @Fecha) ");
                sb.Append(" SELECT SCOPE_IDENTITY()");

                cmd.Parameters.AddWithValue("@NroFact", cobro.NumeroFactura);
                cmd.Parameters.AddWithValue("@IdAlu", cobro.IdAlumno);
                cmd.Parameters.AddWithValue("@Fecha", cobro.Fecha);

                cmd.CommandText = sb.ToString();
                cobro.IdCobro = int.Parse(cmd.ExecuteScalar().ToString());

                // se guardan los detalles

                sb.Clear();
                //cmd.Parameters.Clear();

                sb.Append("INSERT INTO DetalleCobro(IdCobro, IdCuotaMatricula, Monto) VALUES(@IdCobro, @IdCuota, @Monto)");
                cmd.CommandText = sb.ToString();
                foreach (var d in detalle)
                {
                    cmd.Parameters.AddWithValue("@IdCobro", cobro.IdCobro);
                    cmd.Parameters.AddWithValue("@IdCuota", d.IdCuotaMatricula);
                    cmd.Parameters.AddWithValue("@Monto", d.Monto);

                    cmd.ExecuteNonQuery();
                cmd.Parameters.Clear();
                }

                tran.Commit();
            }
            catch (SqlException ex)
            {
                if (tran != null)
                {
                    tran.Rollback();
                }
                throw new Exception("No se pudo registrar el cobro");
            }
            finally
            {
                if (conn != null && conn.State == ConnectionState.Open)
                {
                    conn.Close();
                }
            }
        }

        public static List<DetalleCobro> ObtenerDetallesCobro(int idCobro)
        {
            List<DetalleCobro> detalles = new List<DetalleCobro>();
            try
            {
                using (SqlConnection conn = AccesoDato.Conectar())
                {
                    string sql = "SELECT IdDetalleCobro, IdCobro, IdCuotaMatricula, Monto FROM DetalleCobro WHERE IdCobro=@IdCobro";
                    SqlCommand cmd = new SqlCommand(sql, conn);
                    cmd.Parameters.AddWithValue("@IdCobro", idCobro);
                    conn.Open();
                    SqlDataReader dr = cmd.ExecuteReader();

                    while (dr.Read())
                    {
                        detalles.Add(MapearEntidadDetalleCobro(dr));
                    }
                }
                return detalles;
            }
            catch (SqlException ex)
            {
                throw new Exception("No se pudo obtener los detalles del cobro");
            }
        }

        private static Cobro MapearEntidadCobro(SqlDataReader dr)
        {
            int id = dr.GetInt32(0);
            int nroFactura = dr.GetInt32(1);
            int idAlumno = dr.GetInt32(2);
            DateTime fecha = dr.GetDateTime(3);
            return new Cobro()
            {
                IdCobro = id,
                NumeroFactura = nroFactura,
                Fecha = fecha,
                IdAlumno = idAlumno
            };
        }

        private static DetalleCobro MapearEntidadDetalleCobro(SqlDataReader dr)
        {
            int id = dr.GetInt32(0);
            int idCobro = dr.GetInt32(1);
            int idCuotaMatricula = dr.GetInt32(2);
            decimal monto = dr.GetDecimal(3);
            return new DetalleCobro()
            {
                IdDetalleCobro = id,
                IdCobro = idCobro,
                IdCuotaMatricula = idCuotaMatricula,
                Monto = monto
            };
        }
    }
}
